import pygame

class Widget:
    def __init__(self):
        pass
    def handleClick(self,coords,button):
        pass
    def handleMouseOver(self,coords):
        pass
    def update(self):
        pass
    def getRect(self):
        pass


class Image(Widget):
    def __init__(self,image):
        self.surface = image
        
    def update(self):
        return self.surface
    
    def getRect(self):
        return self.surface.get_rect()


class Button(Image):
    def __init__(self,image,command,enabled=True):
        Image.__init__(self,image)
        self.command = command
        self.enabled = enabled
        self.disabledSurface = None
        
    def handleClick(self,coords,button):
        if self.enabled and button == 1:
            self.command.doIt()
            
    def update(self):
        if self.enabled:
            return self.surface
        else:
            if self.disabledSurface == None:
                whiteSurface = pygame.surface.Surface(self.surface.get_size())
                whiteSurface.fill((128,128,128))
                whiteSurface.set_alpha(192)
                self.disabledSurface = self.surface.copy()
                self.disabledSurface.blit(whiteSurface,(0,0))
            return self.disabledSurface


class ScrollPane(Widget):
    def __init__(self,size,clientWidget,scrollUnit):
        self.clientWidget = clientWidget
        self.surface = pygame.surface.Surface(size)
        self.rect = pygame.Rect((0,0),size)
        self.scrollRect = self.rect.move((0,0))
        self.scrollUnit = scrollUnit
        
    def update(self):
        #return self.clientWidget.update().subsurface(self.scrollRect)
        location = (-self.scrollRect.left,-self.scrollRect.top)
        self.surface.blit(self.clientWidget.update(),location)
        return self.surface
        
    def getRect(self):
        return self.rect
    
    def scroll(self,changeInUnits):
        change = (changeInUnits[0]*self.scrollUnit,changeInUnits[1]*self.scrollUnit)
        self.scrollRect.move_ip(change)
        self.clamp()
            
    def resetScroll(self):
        self.scrollRect.move_ip((0,0))
    
    # Scroll to a particular point in the client.
    def scrollToPoint(self,point):
        self.scrollRect.center = point
        self.clamp()
        
    def clamp(self):
        clientRect = self.clientWidget.getRect()
        self.scrollRect.clamp_ip(clientRect)
    
    def handleClick(self,coords,button):
        # If they used the scroll wheel...
        if button == 4:
            # Scroll up:
            self.scroll((0,-1))
        elif button == 5:
            # Scroll down:
            self.scroll((0,1))
        # Otherwise, pass the event on to the client widget...
        else:
            localCoords = self.getLocalCoords(coords)
            if localCoords:
                self.clientWidget.handleClick(localCoords,button)
    
    def handleMouseOver(self,coords):
        localCoords = self.getLocalCoords(coords)
        if localCoords:
            self.clientWidget.handleMouseOver(localCoords)
    
    def getLocalCoords(self,coords):
        localCoords = self.scrollRect.move(coords).topleft
        if self.clientWidget.getRect().collidepoint(localCoords):
            return localCoords
        else:
            return None
        
    def isPointVisible(self,coordsInClient):
        return self.scrollRect.collidepoint(coordsInClient)


class Panel(Widget):
    def __init__(self):
        pass
        
    def handleClick(self,coords,button):
        widget = self.getWidgetAtPoint(coords)
        if widget:
            localCoords = self.getLocalCoords(widget,coords)
            widget.handleClick(localCoords,button)
    
    def handleMouseOver(self,coords):
        widget = self.getWidgetAtPoint(coords)
        if widget:
            localCoords = self.getLocalCoords(widget,coords)
            widget.handleMouseOver(localCoords)
        
    def getWidgetAtPoint(self,coords):
        # Abstract
        pass
    
    def getLocalCoords(self,widget,coords):
        # Abstract
        pass


class CoordPanel(Panel):
    def __init__(self,size,widgetCoordMap):
        Panel.__init__(self)
        self.widgetCoordMap = widgetCoordMap
        self.surface = pygame.surface.Surface(size)
        self.rect = self.surface.get_rect()
    
    def getWidgetAtPoint(self,coords):
        for widget,pos in self.widgetCoordMap.iteritems():
            rect = widget.getRect().move(pos)
            if rect.collidepoint(coords):
                return widget
        return None
    
    def getLocalCoords(self,widget,coords):
        widgetLocation = self.widgetCoordMap[widget]
        x = coords[0] - widgetLocation[0]
        y = coords[1] - widgetLocation[1]
        return (x,y)
    
    def update(self):
        self.surface.fill((255,255,255))
        for widget,coords in self.widgetCoordMap.iteritems():
            self.surface.blit(widget.update(),coords)
        return self.surface
    
    def getRect(self):
        return self.rect


class StackPanel(Panel):
    def __init__(self,width):
        Panel.__init__(self)
        self.surface = pygame.surface.Surface((width,1))
        self.rect = self.surface.get_rect()
        self.widgets = []
        
    def update(self):
        self.surface.fill((255,255,255))
        yPos = 0
        for widget in self.widgets:
            self.surface.blit(widget.update(),(0,yPos))
            yPos += widget.getRect().height
        if yPos > self.rect.height:
            self.surface = pygame.surface.Surface((self.rect.width,yPos))
            self.rect = self.surface.get_rect()
            self.update()
        if yPos < self.rect.height:
            oldSurface = self.surface
            self.surface = pygame.surface.Surface((self.rect.width,yPos))
            self.rect = self.surface.get_rect()
            self.surface.blit(oldSurface,(0,0))
        return self.surface
        
    def getWidgetAtPoint(self,coords):
        yPos = 0
        for widget in self.widgets:
            rect = widget.getRect().move(0,yPos)
            if rect.collidepoint(coords):
                return widget
            yPos += rect.height
        return None
    
    def getLocalCoords(self,widget,coords):
        yPos = 0
        for otherWidget in self.widgets:
            if otherWidget == widget:
                return (coords[0],coords[1]-yPos)
            else:
                yPos += otherWidget.getRect().height
                
    def getRect(self):
        return self.rect
    